/**
 * @file stlfutils.cpp
 * @brief File utilities - Fixed for Unicode compatibility
 */

#include "stlfutils.h"
#include "stlstrings.h"

#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#endif

#include <fstream>

using namespace std;

bool FileExists(const CString& FilePath)
{
#ifdef _WIN32
    DWORD attr = GetFileAttributes(FilePath.wc_str());
    return (attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY));
#else
    struct stat st;
    return (stat(FilePath.c_str(), &st) == 0 && S_ISREG(st.st_mode));
#endif
}

bool DirExists(const CString& DirPath)
{
#ifdef _WIN32
    DWORD attr = GetFileAttributes(DirPath.wc_str());
    return (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY));
#else
    struct stat st;
    return (stat(DirPath.c_str(), &st) == 0 && S_ISDIR(st.st_mode));
#endif
}

bool MakeDir(const CString& DirPath, int DirMode)
{
#ifdef _WIN32
    (void)DirMode; // Unused on Windows
    return CreateDirectory(DirPath.wc_str(), NULL);
#else
    return mkdir(DirPath.c_str(), DirMode) == 0;
#endif
}

CString CurrentDirPath()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH_LENGTH];
    if (GetCurrentDirectory(MAX_PATH_LENGTH, path))
        return CString(path);
    return CString();
#else
    char path[MAX_PATH_LENGTH];
    if (getcwd(path, MAX_PATH_LENGTH))
        return CString(path);
    return CString();
#endif
}

CString TempDirPath()
{
#ifdef _WIN32
    wchar_t tmp[MAX_PATH_LENGTH];
    if (GetTempPath(MAX_PATH_LENGTH, tmp))
        return CString(tmp);
    return CString();
#else
    const char* tmp = getenv("TMPDIR");
    if (tmp) return CString(tmp);
    tmp = getenv("TMP");
    if (tmp) return CString(tmp);
    tmp = getenv("TEMP");
    if (tmp) return CString(tmp);
    return CString("/tmp");
#endif
}

CString HomeDirPath()
{
#ifdef _WIN32
    const wchar_t* home = _wgetenv(L"USERPROFILE");
    if (home) return CString(home);
    home = _wgetenv(L"HOMEDRIVE");
    const wchar_t* homepath = _wgetenv(L"HOMEPATH");
    if (home && homepath) {
        CString result(home);
        result += homepath;
        return result;
    }
    return CString();
#else
    const char* home = getenv("HOME");
    if (home) return CString(home);
    return CString();
#endif
}

bool ReadFileAsString(const CString& FilePath, CString& Content)
{
    ifstream file(FilePath.c_str());
    if (!file.is_open()) return false;
    
    string content((istreambuf_iterator<char>(file)), istreambuf_iterator<char>());
    Content = CString(content.c_str());
    return true;
}

bool WriteStringToFile(const CString& FilePath, const CString& Content)
{
    ofstream file(FilePath.c_str());
    if (!file.is_open()) return false;
    
    file << Content.c_str();
    return true;
}

CString GetFileExtension(const CString& FilePath)
{
    size_t pos = FilePath.rfind('.');
    if (pos != CString::npos && pos > FilePath.rfind('/') && pos > FilePath.rfind('\\'))
        return FilePath.substr(pos + 1);
    return CString();
}

CString GetFileName(const CString& FilePath)
{
    size_t pos1 = FilePath.rfind('/');
    size_t pos2 = FilePath.rfind('\\');
    size_t pos = (pos1 != CString::npos) ? pos1 : CString::npos;
    if (pos2 != CString::npos && (pos == CString::npos || pos2 > pos))
        pos = pos2;
    
    if (pos != CString::npos)
        return FilePath.substr(pos + 1);
    return FilePath;
}

CString GetFileDirectory(const CString& FilePath)
{
    size_t pos1 = FilePath.rfind('/');
    size_t pos2 = FilePath.rfind('\\');
    size_t pos = (pos1 != CString::npos) ? pos1 : CString::npos;
    if (pos2 != CString::npos && (pos == CString::npos || pos2 > pos))
        pos = pos2;
    
    if (pos != CString::npos)
        return FilePath.substr(0, pos);
    return CString();
}

bool CopyFile(const CString& Source, const CString& Destination)
{
#ifdef _WIN32
    return CopyFileW(Source.wc_str(), Destination.wc_str(), FALSE) != 0;
#else
    ifstream src(Source.c_str(), ios::binary);
    ofstream dst(Destination.c_str(), ios::binary);
    
    if (!src.is_open() || !dst.is_open()) return false;
    
    dst << src.rdbuf();
    return true;
#endif
}

bool DeleteFile(const CString& FilePath)
{
#ifdef _WIN32
    return DeleteFileW(FilePath.wc_str()) != 0;
#else
    return remove(FilePath.c_str()) == 0;
#endif
}

bool RenameFile(const CString& OldPath, const CString& NewPath)
{
#ifdef _WIN32
    return MoveFileW(OldPath.wc_str(), NewPath.wc_str()) != 0;
#else
    return rename(OldPath.c_str(), NewPath.c_str()) == 0;
#endif
}

uint64_t GetFileSize(const CString& FilePath)
{
#ifdef _WIN32
    WIN32_FILE_ATTRIBUTE_DATA fad;
    if (GetFileAttributesExW(FilePath.wc_str(), GetFileExInfoStandard, &fad)) {
        return (static_cast<uint64_t>(fad.nFileSizeHigh) << 32) | fad.nFileSizeLow;
    }
    return 0;
#else
    struct stat st;
    if (stat(FilePath.c_str(), &st) == 0) {
        return static_cast<uint64_t>(st.st_size);
    }
    return 0;
#endif
}
